home *** CD-ROM | disk | FTP | other *** search
/ Aminet 25 / Aminet 25 (1998)(GTI - Schatztruhe)[!][Jun 1998].iso / Aminet / game / shoot / ADoom_src_1_2.lha / ADoom_src / p_inter.c < prev    next >
C/C++ Source or Header  |  1998-02-24  |  22KB  |  928 lines

  1. // Emacs style mode select   -*- C++ -*- 
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:
  20. //      Handling interactions (i.e., collisions).
  21. //
  22. //-----------------------------------------------------------------------------
  23.  
  24.  
  25. static const char
  26. rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $";
  27.  
  28.  
  29. // Data.
  30. #include "doomdef.h"
  31. #include "dstrings.h"
  32. #include "sounds.h"
  33.  
  34. #include "doomstat.h"
  35.  
  36. #include "m_random.h"
  37. #include "i_system.h"
  38.  
  39. #include "am_map.h"
  40.  
  41. #include "p_local.h"
  42.  
  43. #include "s_sound.h"
  44.  
  45. #ifdef __GNUG__
  46. #pragma implementation "p_inter.h"
  47. #endif
  48. #include "p_inter.h"
  49.  
  50.  
  51. #define BONUSADD        6
  52.  
  53.  
  54.  
  55.  
  56. // a weapon is found with two clip loads,
  57. // a big item has five clip loads
  58. int     maxammo[NUMAMMO] = {200, 50, 300, 50};
  59. int     clipammo[NUMAMMO] = {10, 4, 20, 1};
  60.  
  61. // Dehacked
  62. int     MAXHEALTH = 100;
  63.  
  64. //
  65. // GET STUFF
  66. //
  67.  
  68. //
  69. // P_GiveAmmo
  70. // Num is the number of clip loads,
  71. // not the individual count (0= 1/2 clip).
  72. // Returns false if the ammo can't be picked up at all
  73. //
  74.  
  75. boolean
  76. P_GiveAmmo
  77. ( player_t*     player,
  78.   ammotype_t    ammo,
  79.   int           num )
  80. {
  81.     int         oldammo;
  82.         
  83.     if (ammo == am_noammo)
  84.         return false;
  85.                 
  86.     if (ammo < 0 || ammo > NUMAMMO)
  87.         I_Error ("P_GiveAmmo: bad type %i", ammo);
  88.                 
  89.     if ( player->ammo[ammo] == player->maxammo[ammo]  )
  90.         return false;
  91.                 
  92.     if (num)
  93.         num *= clipammo[ammo];
  94.     else
  95.         num = clipammo[ammo]/2;
  96.     
  97.     if (gameskill == sk_baby
  98.         || gameskill == sk_nightmare)
  99.     {
  100.         // give double ammo in trainer mode,
  101.         // you'll need in nightmare
  102.         num <<= 1;
  103.     }
  104.     
  105.                 
  106.     oldammo = player->ammo[ammo];
  107.     player->ammo[ammo] += num;
  108.  
  109.     if (player->ammo[ammo] > player->maxammo[ammo])
  110.         player->ammo[ammo] = player->maxammo[ammo];
  111.  
  112.     // If non zero ammo, 
  113.     // don't change up weapons,
  114.     // player was lower on purpose.
  115.     if (oldammo)
  116.         return true;    
  117.  
  118.     // We were down to zero,
  119.     // so select a new weapon.
  120.     // Preferences are not user selectable.
  121.     switch (ammo)
  122.     {
  123.       case am_clip:
  124.         if (player->readyweapon == wp_fist)
  125.         {
  126.             if (player->weaponowned[wp_chaingun])
  127.                 player->pendingweapon = wp_chaingun;
  128.             else
  129.                 player->pendingweapon = wp_pistol;
  130.         }
  131.         break;
  132.         
  133.       case am_shell:
  134.         if (player->readyweapon == wp_fist
  135.             || player->readyweapon == wp_pistol)
  136.         {
  137.             if (player->weaponowned[wp_shotgun])
  138.                 player->pendingweapon = wp_shotgun;
  139.         }
  140.         break;
  141.         
  142.       case am_cell:
  143.         if (player->readyweapon == wp_fist
  144.             || player->readyweapon == wp_pistol)
  145.         {
  146.             if (player->weaponowned[wp_plasma])
  147.                 player->pendingweapon = wp_plasma;
  148.         }
  149.         break;
  150.         
  151.       case am_misl:
  152.         if (player->readyweapon == wp_fist)
  153.         {
  154.             if (player->weaponowned[wp_missile])
  155.                 player->pendingweapon = wp_missile;
  156.         }
  157.       default:
  158.         break;
  159.     }
  160.         
  161.     return true;
  162. }
  163.  
  164.  
  165. //
  166. // P_GiveWeapon
  167. // The weapon name may have a MF_DROPPED flag ored in.
  168. //
  169. boolean
  170. P_GiveWeapon
  171. ( player_t*     player,
  172.   weapontype_t  weapon,
  173.   boolean       dropped )
  174. {
  175.     boolean     gaveammo;
  176.     boolean     gaveweapon;
  177.         
  178.     if (netgame
  179.         && (deathmatch!=2)
  180.          && !dropped )
  181.     {
  182.         // leave placed weapons forever on net games
  183.         if (player->weaponowned[weapon])
  184.             return false;
  185.  
  186.         player->bonuscount += BONUSADD;
  187.         player->weaponowned[weapon] = true;
  188.  
  189.         if (deathmatch)
  190.             P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
  191.         else
  192.             P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
  193.         player->pendingweapon = weapon;
  194.  
  195.         if (player == &players[consoleplayer])
  196.             S_StartSound (NULL, sfx_wpnup);
  197.         return false;
  198.     }
  199.         
  200.     if (weaponinfo[weapon].ammo != am_noammo)
  201.     {
  202.         // give one clip with a dropped weapon,
  203.         // two clips with a found weapon
  204.         if (dropped)
  205.             gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
  206.         else
  207.             gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
  208.     }
  209.     else
  210.         gaveammo = false;
  211.         
  212.     if (player->weaponowned[weapon])
  213.         gaveweapon = false;
  214.     else
  215.     {
  216.         gaveweapon = true;
  217.         player->weaponowned[weapon] = true;
  218.         player->pendingweapon = weapon;
  219.     }
  220.         
  221.     return (gaveweapon || gaveammo);
  222. }
  223.  
  224.  
  225.  
  226. //
  227. // P_GiveBody
  228. // Returns false if the body isn't needed at all
  229. //
  230. boolean
  231. P_GiveBody
  232. ( player_t*     player,
  233.   int           num )
  234. {
  235.     if (player->health >= MAXHEALTH)
  236.         return false;
  237.                 
  238.     player->health += num;
  239.     if (player->health > MAXHEALTH)
  240.         player->health = MAXHEALTH;
  241.     player->mo->health = player->health;
  242.         
  243.     return true;
  244. }
  245.  
  246.  
  247.  
  248. //
  249. // P_GiveArmor
  250. // Returns false if the armor is worse
  251. // than the current armor.
  252. //
  253. boolean
  254. P_GiveArmor
  255. ( player_t*     player,
  256.   int           armortype )
  257. {
  258.     int         hits;
  259.         
  260.     hits = armortype*100;
  261.     if (player->armorpoints >= hits)
  262.         return false;   // don't pick up
  263.                 
  264.     player->armortype = armortype;
  265.     player->armorpoints = hits;
  266.         
  267.     return true;
  268. }
  269.  
  270.  
  271.  
  272. //
  273. // P_GiveCard
  274. //
  275. void
  276. P_GiveCard
  277. ( player_t*     player,
  278.   card_t        card )
  279. {
  280.     if (player->cards[card])
  281.         return;
  282.     
  283.     player->bonuscount = BONUSADD;
  284.     player->cards[card] = 1;
  285. }
  286.  
  287.  
  288. //
  289. // P_GivePower
  290. //
  291. boolean
  292. P_GivePower
  293. ( player_t*     player,
  294.   int /*powertype_t*/   power )
  295. {
  296.     if (power == pw_invulnerability)
  297.     {
  298.         player->powers[power] = INVULNTICS;
  299.         return true;
  300.     }
  301.     
  302.     if (power == pw_invisibility)
  303.     {
  304.         player->powers[power] = INVISTICS;
  305.         player->mo->flags |= MF_SHADOW;
  306.         return true;
  307.     }
  308.     
  309.     if (power == pw_infrared)
  310.     {
  311.         player->powers[power] = INFRATICS;
  312.         return true;
  313.     }
  314.     
  315.     if (power == pw_ironfeet)
  316.     {
  317.         player->powers[power] = IRONTICS;
  318.         return true;
  319.     }
  320.     
  321.     if (power == pw_strength)
  322.     {
  323.         P_GiveBody (player, 100);
  324.         player->powers[power] = 1;
  325.         return true;
  326.     }
  327.         
  328.     if (player->powers[power])
  329.         return false;   // already got it
  330.                 
  331.     player->powers[power] = 1;
  332.     return true;
  333. }
  334.  
  335.  
  336. // Dehacked
  337. int max_armor=200;
  338. int green_armor_class=1;
  339. int blue_armor_class=2;
  340. int maxsoul=200;
  341. int soul_health=100;
  342. int mega_health=200;
  343.  
  344. //
  345. // P_TouchSpecialThing
  346. //
  347. void
  348. P_TouchSpecialThing
  349. ( mobj_t*       special,
  350.   mobj_t*       toucher )
  351. {
  352.     player_t*   player;
  353.     int         i;
  354.     fixed_t     delta;
  355.     int         sound;
  356.                 
  357.     delta = special->z - toucher->z;
  358.  
  359.     if (delta > toucher->height
  360.         || delta < -8*FRACUNIT)
  361.     {
  362.         // out of reach
  363.         return;
  364.     }
  365.     
  366.         
  367.     sound = sfx_itemup; 
  368.     player = toucher->player;
  369.  
  370.     // Dead thing touching.
  371.     // Can happen with a sliding player corpse.
  372.     if (toucher->health <= 0)
  373.         return;
  374.  
  375.     // Identify by sprite.
  376.     switch (special->sprite)
  377.     {
  378.         // armor
  379.       case SPR_ARM1:
  380.         if (!P_GiveArmor (player, green_armor_class))
  381.             return;
  382.         player->message = GOTARMOR;
  383.         break;
  384.                 
  385.       case SPR_ARM2:
  386.         if (!P_GiveArmor (player, blue_armor_class))
  387.             return;
  388.         player->message = GOTMEGA;
  389.         break;
  390.         
  391.         // bonus items
  392.       case SPR_BON1:
  393.         player->health++;               // can go over 100%
  394.         if (player->health > 2*MAXHEALTH)
  395.             player->health = 2*MAXHEALTH;
  396.         player->mo->health = player->health;
  397.         player->message = GOTHTHBONUS;
  398.         break;
  399.         
  400.       case SPR_BON2:
  401.         player->armorpoints++;          // can go over 100%
  402.         if (player->armorpoints > max_armor)
  403.             player->armorpoints = max_armor;
  404.         if (!player->armortype)
  405.             player->armortype = 1;
  406.         player->message = GOTARMBONUS;
  407.         break;
  408.         
  409.       case SPR_SOUL:
  410.         player->health += soul_health;
  411.         if (player->health > maxsoul)
  412.             player->health = maxsoul;
  413.         player->mo->health = player->health;
  414.         player->message = GOTSUPER;
  415.         sound = sfx_getpow;
  416.         break;
  417.         
  418.       case SPR_MEGA:
  419.         if (gamemode != commercial)
  420.             return;
  421.         player->health = mega_health;
  422.         player->mo->health = player->health;
  423.         P_GiveArmor (player,2);
  424.         player->message = GOTMSPHERE;
  425.         sound = sfx_getpow;
  426.         break;
  427.         
  428.         // cards
  429.         // leave cards for everyone
  430.       case SPR_BKEY:
  431.         if (!player->cards[it_bluecard])
  432.             player->message = GOTBLUECARD;
  433.         P_GiveCard (player, it_bluecard);
  434.         if (!netgame)
  435.             break;
  436.         return;
  437.         
  438.       case SPR_YKEY:
  439.         if (!player->cards[it_yellowcard])
  440.             player->message = GOTYELWCARD;
  441.         P_GiveCard (player, it_yellowcard);
  442.         if (!netgame)
  443.             break;
  444.         return;
  445.         
  446.       case SPR_RKEY:
  447.         if (!player->cards[it_redcard])
  448.             player->message = GOTREDCARD;
  449.         P_GiveCard (player, it_redcard);
  450.         if (!netgame)
  451.             break;
  452.         return;
  453.         
  454.       case SPR_BSKU:
  455.         if (!player->cards[it_blueskull])
  456.             player->message = GOTBLUESKUL;
  457.         P_GiveCard (player, it_blueskull);
  458.         if (!netgame)
  459.             break;
  460.         return;
  461.         
  462.       case SPR_YSKU:
  463.         if (!player->cards[it_yellowskull])
  464.             player->message = GOTYELWSKUL;
  465.         P_GiveCard (player, it_yellowskull);
  466.         if (!netgame)
  467.             break;
  468.         return;
  469.         
  470.       case SPR_RSKU:
  471.         if (!player->cards[it_redskull])
  472.             player->message = GOTREDSKULL;
  473.         P_GiveCard (player, it_redskull);
  474.         if (!netgame)
  475.             break;
  476.         return;
  477.         
  478.         // medikits, heals
  479.       case SPR_STIM:
  480.         if (!P_GiveBody (player, 10))
  481.             return;
  482.         player->message = GOTSTIM;
  483.         break;
  484.         
  485.       case SPR_MEDI:
  486.         if (!P_GiveBody (player, 25))
  487.             return;
  488.  
  489.         if (player->health < 25)
  490.             player->message = GOTMEDINEED;
  491.         else
  492.             player->message = GOTMEDIKIT;
  493.         break;
  494.  
  495.         
  496.         // power ups
  497.       case SPR_PINV:
  498.         if (!P_GivePower (player, pw_invulnerability))
  499.             return;
  500.         player->message = GOTINVUL;
  501.         sound = sfx_getpow;
  502.         break;
  503.         
  504.       case SPR_PSTR:
  505.         if (!P_GivePower (player, pw_strength))
  506.             return;
  507.         player->message = GOTBERSERK;
  508.         if (player->readyweapon != wp_fist)
  509.             player->pendingweapon = wp_fist;
  510.         sound = sfx_getpow;
  511.         break;
  512.         
  513.       case SPR_PINS:
  514.         if (!P_GivePower (player, pw_invisibility))
  515.             return;
  516.         player->message = GOTINVIS;
  517.         sound = sfx_getpow;
  518.         break;
  519.         
  520.       case SPR_SUIT:
  521.         if (!P_GivePower (player, pw_ironfeet))
  522.             return;
  523.         player->message = GOTSUIT;
  524.         sound = sfx_getpow;
  525.         break;
  526.         
  527.       case SPR_PMAP:
  528.         if (!P_GivePower (player, pw_allmap))
  529.             return;
  530.         player->message = GOTMAP;
  531.         sound = sfx_getpow;
  532.         break;
  533.         
  534.       case SPR_PVIS:
  535.         if (!P_GivePower (player, pw_infrared))
  536.             return;
  537.         player->message = GOTVISOR;
  538.         sound = sfx_getpow;
  539.         break;
  540.         
  541.         // ammo
  542.       case SPR_CLIP:
  543.         if (special->flags & MF_DROPPED)
  544.         {
  545.             if (!P_GiveAmmo (player,am_clip,0))
  546.                 return;
  547.         }
  548.         else
  549.         {
  550.             if (!P_GiveAmmo (player,am_clip,1))
  551.                 return;
  552.         }
  553.         player->message = GOTCLIP;
  554.         break;
  555.         
  556.       case SPR_AMMO:
  557.         if (!P_GiveAmmo (player, am_clip,5))
  558.             return;
  559.         player->message = GOTCLIPBOX;
  560.         break;
  561.         
  562.       case SPR_ROCK:
  563.         if (!P_GiveAmmo (player, am_misl,1))
  564.             return;
  565.         player->message = GOTROCKET;
  566.         break;
  567.         
  568.       case SPR_BROK:
  569.         if (!P_GiveAmmo (player, am_misl,5))
  570.             return;
  571.         player->message = GOTROCKBOX;
  572.         break;
  573.         
  574.       case SPR_CELL:
  575.         if (!P_GiveAmmo (player, am_cell,1))
  576.             return;
  577.         player->message = GOTCELL;
  578.         break;
  579.         
  580.       case SPR_CELP:
  581.         if (!P_GiveAmmo (player, am_cell,5))
  582.             return;
  583.         player->message = GOTCELLBOX;
  584.         break;
  585.         
  586.       case SPR_SHEL:
  587.         if (!P_GiveAmmo (player, am_shell,1))
  588.             return;
  589.         player->message = GOTSHELLS;
  590.         break;
  591.         
  592.       case SPR_SBOX:
  593.         if (!P_GiveAmmo (player, am_shell,5))
  594.             return;
  595.         player->message = GOTSHELLBOX;
  596.         break;
  597.         
  598.       case SPR_BPAK:
  599.         if (!player->backpack)
  600.         {
  601.             for (i=0 ; i<NUMAMMO ; i++)
  602.                 player->maxammo[i] *= 2;
  603.             player->backpack = true;
  604.         }
  605.         for (i=0 ; i<NUMAMMO ; i++)
  606.             P_GiveAmmo (player, i, 1);
  607.         player->message = GOTBACKPACK;
  608.         break;
  609.         
  610.         // weapons
  611.       case SPR_BFUG:
  612.         if (!P_GiveWeapon (player, wp_bfg, false) )
  613.             return;
  614.         player->message = GOTBFG9000;
  615.         sound = sfx_wpnup;      
  616.         break;
  617.         
  618.       case SPR_MGUN:
  619.         if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
  620.             return;
  621.         player->message = GOTCHAINGUN;
  622.         sound = sfx_wpnup;      
  623.         break;
  624.         
  625.       case SPR_CSAW:
  626.         if (!P_GiveWeapon (player, wp_chainsaw, false) )
  627.             return;
  628.         player->message = GOTCHAINSAW;
  629.         sound = sfx_wpnup;      
  630.         break;
  631.         
  632.       case SPR_LAUN:
  633.         if (!P_GiveWeapon (player, wp_missile, false) )
  634.             return;
  635.         player->message = GOTLAUNCHER;
  636.         sound = sfx_wpnup;      
  637.         break;
  638.         
  639.       case SPR_PLAS:
  640.         if (!P_GiveWeapon (player, wp_plasma, false) )
  641.             return;
  642.         player->message = GOTPLASMA;
  643.         sound = sfx_wpnup;      
  644.         break;
  645.         
  646.       case SPR_SHOT:
  647.         if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
  648.             return;
  649.         player->message = GOTSHOTGUN;
  650.         sound = sfx_wpnup;      
  651.         break;
  652.                 
  653.       case SPR_SGN2:
  654.         if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
  655.             return;
  656.         player->message = GOTSHOTGUN2;
  657.         sound = sfx_wpnup;      
  658.         break;
  659.                 
  660.       default:
  661.         I_Error ("P_SpecialThing: Unknown gettable thing");
  662.     }
  663.         
  664.     if (special->flags & MF_COUNTITEM)
  665.         player->itemcount++;
  666.     P_RemoveMobj (special);
  667.     player->bonuscount += BONUSADD;
  668.     if (player == &players[consoleplayer])
  669.         S_StartSound (NULL, sound);
  670. }
  671.  
  672.  
  673. //
  674. // KillMobj
  675. //
  676. void
  677. P_KillMobj
  678. ( mobj_t*       source,
  679.   mobj_t*       target )
  680. {
  681.     mobjtype_t  item;
  682.     mobj_t*     mo;
  683.         
  684.     target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
  685.  
  686.     if (target->type != MT_SKULL)
  687.         target->flags &= ~MF_NOGRAVITY;
  688.  
  689.     target->flags |= MF_CORPSE|MF_DROPOFF;
  690.     target->height >>= 2;
  691.  
  692.     if (source && source->player)
  693.     {
  694.         // count for intermission
  695.         if (target->flags & MF_COUNTKILL)
  696.             source->player->killcount++;        
  697.  
  698.         if (target->player)
  699.             source->player->frags[target->player-players]++;
  700.     }
  701.     else if (!netgame && (target->flags & MF_COUNTKILL) )
  702.     {
  703.         // count all monster deaths,
  704.         // even those caused by other monsters
  705.         players[0].killcount++;
  706.     }
  707.     
  708.     if (target->player)
  709.     {
  710.         // count environment kills against you
  711.         if (!source)    
  712.             target->player->frags[target->player-players]++;
  713.                         
  714.         target->flags &= ~MF_SOLID;
  715.         target->player->playerstate = PST_DEAD;
  716.         P_DropWeapon (target->player);
  717.  
  718.         if (target->player == &players[consoleplayer]
  719.             && automapactive)
  720.         {
  721.             // don't die in auto map,
  722.             // switch view prior to dying
  723.             AM_Stop ();
  724.         }
  725.         
  726.     }
  727.  
  728.     if (target->health < -target->info->spawnhealth 
  729.         && target->info->xdeathstate)
  730.     {
  731.         P_SetMobjState (target, target->info->xdeathstate);
  732.     }
  733.     else
  734.         P_SetMobjState (target, target->info->deathstate);
  735.     target->tics -= P_Random()&3;
  736.  
  737.     if (target->tics < 1)
  738.         target->tics = 1;
  739.                 
  740.     //  I_StartSound (&actor->r, actor->info->deathsound);
  741.  
  742.  
  743.     // Drop stuff.
  744.     // This determines the kind of object spawned
  745.     // during the death frame of a thing.
  746.     switch (target->type)
  747.     {
  748.       case MT_WOLFSS:
  749.       case MT_POSSESSED:
  750.         item = MT_CLIP;
  751.         break;
  752.         
  753.       case MT_SHOTGUY:
  754.         item = MT_SHOTGUN;
  755.         break;
  756.         
  757.       case MT_CHAINGUY:
  758.         item = MT_CHAINGUN;
  759.         break;
  760.         
  761.       default:
  762.         return;
  763.     }
  764.  
  765.     mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
  766.     mo->flags |= MF_DROPPED;    // special versions of items
  767. }
  768.  
  769.  
  770.  
  771.  
  772. //
  773. // P_DamageMobj
  774. // Damages both enemies and players
  775. // "inflictor" is the thing that caused the damage
  776. //  creature or missile, can be NULL (slime, etc)
  777. // "source" is the thing to target after taking damage
  778. //  creature or NULL
  779. // Source and inflictor are the same for melee attacks.
  780. // Source can be NULL for slime, barrel explosions
  781. // and other environmental stuff.
  782. //
  783. void
  784. P_DamageMobj
  785. ( mobj_t*       target,
  786.   mobj_t*       inflictor,
  787.   mobj_t*       source,
  788.   int           damage )
  789. {
  790.     unsigned    ang;
  791.     int         saved;
  792.     player_t*   player;
  793.     fixed_t     thrust;
  794.     int         temp;
  795.         
  796.     if ( !(target->flags & MF_SHOOTABLE) )
  797.         return; // shouldn't happen...
  798.                 
  799.     if (target->health <= 0)
  800.         return;
  801.  
  802.     if ( target->flags & MF_SKULLFLY )
  803.     {
  804.         target->momx = target->momy = target->momz = 0;
  805.     }
  806.         
  807.     player = target->player;
  808.     if (player && gameskill == sk_baby)
  809.         damage >>= 1;   // take half damage in trainer mode
  810.                 
  811.  
  812.     // Some close combat weapons should not
  813.     // inflict thrust and push the victim out of reach,
  814.     // thus kick away unless using the chainsaw.
  815.     if (inflictor
  816.         && !(target->flags & MF_NOCLIP)
  817.         && (!source
  818.             || !source->player
  819.             || source->player->readyweapon != wp_chainsaw))
  820.     {
  821.         ang = R_PointToAngle2 ( inflictor->x,
  822.                                 inflictor->y,
  823.                                 target->x,
  824.                                 target->y);
  825.                 
  826.         thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
  827.  
  828.         // make fall forwards sometimes
  829.         if ( damage < 40
  830.              && damage > target->health
  831.              && target->z - inflictor->z > 64*FRACUNIT
  832.              && (P_Random ()&1) )
  833.         {
  834.             ang += ANG180;
  835.             thrust *= 4;
  836.         }
  837.                 
  838.         ang >>= ANGLETOFINESHIFT;
  839.         target->momx += FixedMul (thrust, finecosine[ang]);
  840.         target->momy += FixedMul (thrust, finesine[ang]);
  841.     }
  842.     
  843.     // player specific
  844.     if (player)
  845.     {
  846.         // end of game hell hack
  847.         if (target->subsector->sector->special == 11
  848.             && damage >= target->health)
  849.         {
  850.             damage = target->health - 1;
  851.         }
  852.         
  853.  
  854.         // Below certain threshold,
  855.         // ignore damage in GOD mode, or with INVUL power.
  856.         if ( damage < 1000
  857.              && ( (player->cheats&CF_GODMODE)
  858.                   || player->powers[pw_invulnerability] ) )
  859.         {
  860.             return;
  861.         }
  862.         
  863.         if (player->armortype)
  864.         {
  865.             if (player->armortype == 1)
  866.                 saved = damage/3;
  867.             else
  868.                 saved = damage/2;
  869.             
  870.             if (player->armorpoints <= saved)
  871.             {
  872.                 // armor is used up
  873.                 saved = player->armorpoints;
  874.                 player->armortype = 0;
  875.             }
  876.             player->armorpoints -= saved;
  877.             damage -= saved;
  878.         }
  879.         player->health -= damage;       // mirror mobj health here for Dave
  880.         if (player->health < 0)
  881.             player->health = 0;
  882.         
  883.         player->attacker = source;
  884.         player->damagecount += damage;  // add damage after armor / invuln
  885.  
  886.         if (player->damagecount > 100)
  887.             player->damagecount = 100;  // teleport stomp does 10k points...
  888.         
  889.         temp = damage < 100 ? damage : 100;
  890.  
  891.         if (player == &players[consoleplayer])
  892.             I_Tactile (40,10,40+temp*2);
  893.     }
  894.     
  895.     // do the damage    
  896.     target->health -= damage;   
  897.     if (target->health <= 0)
  898.     {
  899.         P_KillMobj (source, target);
  900.         return;
  901.     }
  902.  
  903.     if ( (P_Random () < target->info->painchance)
  904.          && !(target->flags&MF_SKULLFLY) )
  905.     {
  906.         target->flags |= MF_JUSTHIT;    // fight back!
  907.         
  908.         P_SetMobjState (target, target->info->painstate);
  909.     }
  910.                         
  911.     target->reactiontime = 0;           // we're awake now...   
  912.  
  913.     if ( (!target->threshold || target->type == MT_VILE)
  914.          && source && source != target
  915.          && source->type != MT_VILE)
  916.     {
  917.         // if not intent on another player,
  918.         // chase after this one
  919.         target->target = source;
  920.         target->threshold = BASETHRESHOLD;
  921.         if (target->state == &states[target->info->spawnstate]
  922.             && target->info->seestate != S_NULL)
  923.             P_SetMobjState (target, target->info->seestate);
  924.     }
  925.                         
  926. }
  927.  
  928.